﻿using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Security.Permissions;
using Microsoft.Practices.Prism.Modularity;
using MyFramework.Common.Attributes;

namespace MyFramework.Core
{
    /// <summary>
    /// order directory module catalog
    /// </summary>
    [SecurityPermission(SecurityAction.InheritanceDemand), SecurityPermission(SecurityAction.LinkDemand)]
    public class OrderDirectoryModuleCatalog : DirectoryModuleCatalog
    {
        /// <summary>
        /// Sorts a list of <see cref="T:Microsoft.Practices.Prism.Modularity.ModuleInfo" />s. This method is called by <see cref="M:Microsoft.Practices.Prism.Modularity.ModuleCatalog.CompleteListWithDependencies(System.Collections.Generic.IEnumerable{Microsoft.Practices.Prism.Modularity.ModuleInfo})" />
        /// to return a sorted list.
        /// </summary>
        /// <param name="modules">The <see cref="T:Microsoft.Practices.Prism.Modularity.ModuleInfo" />s to sort.</param>
        /// <returns>
        /// Sorted list of <see cref="T:Microsoft.Practices.Prism.Modularity.ModuleInfo" />s
        /// </returns>
        protected override IEnumerable<ModuleInfo> Sort(IEnumerable<ModuleInfo> modules)
        {
            var list = base.Sort(modules);

            List<ModuleInfoOrderable> result = new List<ModuleInfoOrderable>();
            foreach (var item in list)
            {
                Assembly dll = Assembly.LoadFrom(item.Ref);
                var attributes = dll.GetType().GetCustomAttributes(typeof(ModuleOrderAttribute), true);
                int position = attributes.Count() > 0 ? attributes.Cast<ModuleOrderAttribute>().Sum(f => f.Order) : 0;

                result.Add(new ModuleInfoOrderable() { Module = item, Order = position });
            }


            return result.OrderBy(r => r.Order).Select(d => d.Module);

        }
    }

    /// <summary>
    /// Module info orderable
    /// </summary>
    public class ModuleInfoOrderable
    {
        /// <summary>
        /// Gets or sets the order.
        /// </summary>
        /// <value>
        /// The order.
        /// </value>
        public int Order { get; set; }

        /// <summary>
        /// Gets or sets the module.
        /// </summary>
        /// <value>
        /// The module.
        /// </value>
        public ModuleInfo Module { get; set; }
    }
}
